package com.framework.bdf4j.sysadm.controller;

import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.framework.bdf4j.annotations.SysLog;
import com.framework.bdf4j.comm.Constants;
import com.framework.bdf4j.comm.exception.ExcelImportException;
import com.framework.bdf4j.comm.mail.MailHelper;
import com.framework.bdf4j.comm.util.AesUtil;
import com.framework.bdf4j.comm.util.R;
import com.framework.bdf4j.comm.util.StringUtils;
import com.framework.bdf4j.comm.util.UserInfoValidator;
import com.framework.bdf4j.comm.web.WebUtil;
import com.framework.bdf4j.sysadm.entity.SysDept;
import com.framework.bdf4j.sysadm.entity.SysRole;
import com.framework.bdf4j.sysadm.entity.SysUser;
import com.framework.bdf4j.sysadm.service.SysDeptService;
import com.framework.bdf4j.sysadm.service.SysFileService;
import com.framework.bdf4j.sysadm.service.SysRoleService;
import com.framework.bdf4j.sysadm.service.SysUserService;
import com.github.liaochong.myexcel.core.DefaultExcelBuilder;
import com.github.liaochong.myexcel.core.SaxExcelReader;
import com.github.liaochong.myexcel.utils.AttachmentExportUtil;

import cn.hutool.core.collection.CollUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@AllArgsConstructor
@RequestMapping("/admin/user")
@Api(value = "user", tags = "用户管理模块")
public class SysUserController {
    private final SysUserService userService;
    private final SysRoleService sysRoleService;
    private final SysFileService sysFileService;
    private final SysDeptService sysDeptService;
    private final MailHelper mailHelper;
    private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();

    // 跳转到用户列表页
    @GetMapping("/index")
    public String goUser() {
        return "sysadm/user/userList";
    }

    // 跳转到用户编辑页
    @GetMapping("/goEditUser")
    public String goEditUser(@RequestParam(required = false) String id, @RequestParam String oper, Model model) {
        SysUser user = new SysUser();
        List<SysRole> allroles = sysRoleService.list(Wrappers.emptyWrapper());
        if (!"add".equals(oper)) {
            user = userService.selectUserVoById(Integer.valueOf(id));
            for (SysRole role : allroles) {
                for (SysRole userRole : user.getRoleList()) {
                    if (role.getRoleId().intValue() == userRole.getRoleId().intValue()) {
                        role.setFlag(true);
                        break;
                    }
                }
            }
        }

        model.addAttribute("viewobject", user);
        model.addAttribute("allroles", allroles);
        model.addAttribute("oper", oper);
        return "sysadm/user/userEdit";
    }

    /**
     * 进入授权角色页
     */
    @GetMapping("/authRole/{userId}")
    public String authRole(@PathVariable("userId") Integer userId, ModelMap mmap) {
        SysUser user = userService.selectUserVoById(userId);
        // 获取用户所属的角色列表
        List<SysRole> userRoles = user.getRoleList();
        mmap.put("user", user);
        mmap.put("userRoles", userRoles);
        return "sysadm/user/userRole";
    }

    /**
     * 分页查询用户
     *
     * @param page
     *            参数集
     * @param userDTO
     *            查询参数列表
     * @return 用户集合
     */
    @GetMapping("/page")
    @ResponseBody
    public R getUserPage(Page page, SysUser userDTO) {
        return R.ok(userService.getUsersWithRolePage(page, userDTO));
    }

    /**
     * 用户状态修改
     */
    @SysLog("修改用户状态")
    @ResponseBody
    @PostMapping("/changeStatus")
    @PreAuthorize("@pms.hasPermission('sys_user_edit')")
    public R changeStatus(SysUser user) {
    	user.setUpdateTime(new Date());
        return R.ok(userService.updateById(user));
    }

    @GetMapping("/resetPwd/{userId}")
    public String resetPwd(@PathVariable("userId") Integer userId, ModelMap mmap) {
        mmap.put("user", userService.selectUserVoById(userId));
        return "sysadm/user/resetPwd";
    }

    @SysLog("重置密码")
    @PostMapping("/resetPwd")
    @ResponseBody
    public R resetPwdSave(SysUser user) {
        if (StringUtils.isEmpty(user.getPassword())) {
            return R.failed("没有找到密码字段");
        }
        // 解密
        user.setPassword(ENCODER.encode(AesUtil.decryptStr(user.getPassword())));
        user.setUpdateTime(new Date());
        return R.ok(userService.updateById(user));
    }

    // 校验用户帐号是否重复
    @ResponseBody
    @PostMapping(value = "/checkAccount")
    public String checkAccount(String accountName, String isowner) {
        String result = "true";

        if (!StringUtils.isEmpty(accountName)) {
            SysUser user = userService.getOne(new QueryWrapper<SysUser>().eq("loginname", accountName));
            if (user != null) {
                if ("false".equals(isowner))
                    result = "false";
            }
        }
        return result;
    }

    // 校验用户帐号是否存在
    @ResponseBody
    @PostMapping(value = "/checkHasAccount")
    public String checkHasAccount(String accountName) {
        String result = "false";

        if (!StringUtils.isEmpty(accountName)) {
            SysUser user = userService.getOne(new QueryWrapper<SysUser>().eq("loginname", accountName));
            if (user != null) {
                result = "true";
            }
        }
        return result;
    }

    // 校验用户手机是否重复
    @ResponseBody
    @PostMapping(value = "/checkPhoneUnique")
    public String checkPhoneUnique(Integer userid, String phone, String isowner) {
        String result = "true";

        if (!StringUtils.isEmpty(phone)) {
            SysUser user = userService.getOne(new QueryWrapper<SysUser>().eq("phone", phone));
            if (user != null) {
                if ("false".equals(isowner))
                    result = "false";
                else if (userid.intValue() != user.getUserId().intValue())
                    result = "false";
            }
        }
        return result;
    }

    // 校验用户邮箱是否重复
    @ResponseBody
    @PostMapping(value = "/checkEmailUnique")
    public String checkEmailUnique(Integer userid, String email, String isowner) {
        String result = "true";

        if (!StringUtils.isEmpty(email)) {
            SysUser user = userService.getOne(new QueryWrapper<SysUser>().eq("email", email));
            if (user != null) {
                if ("false".equals(isowner))
                    result = "false";
                else if (userid.intValue() != user.getUserId().intValue())
                    result = "false";
            }
        }
        return result;
    }

    // 检查验证码是否正确
    @ResponseBody
    @PostMapping(value = "/checkCode")
    public String checkCode(String curCode) {
        String result = "true";
        // 验证码校验
        String code = (String)WebUtil.getHttpSession(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
        if (code == null || (!code.equalsIgnoreCase(curCode))) {
            result = "false";
        }
        return result;
    }

    // 检查动态验证码是否正确
    @ResponseBody
    @PostMapping(value = "/checkFpValidCode")
    public String checkFpValidCode(String curCode) {
        String result = "true";
        // 验证码校验
        String code = (String)WebUtil.getHttpSession(Constants.USER_CHECKCODE);
        if (code == null || (!code.equalsIgnoreCase(curCode))) {
            result = "false";
        }
        return result;
    }

    // 获取动态验证码
    @ResponseBody
    @PostMapping(value = "/getFpValidCode")
    public R getFpValidCode(String loginname, String op, String validatecode) {
        boolean ishasuser = false;
        SysUser user = null;
        if (!StringUtils.isEmpty(loginname)) {
            user = userService.getOne(new QueryWrapper<SysUser>().eq("loginname", loginname));
            if (user != null) {
                ishasuser = true;
            }
        }
        if (!ishasuser) {
            return R.failed("登录名不存在");
        }
        String code = (String)WebUtil.getHttpSession(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
        if (code == null || (!code.equalsIgnoreCase(validatecode))) {
            return R.failed("请输入正确的验证码");
        }
        // 生成验证码，并缓存。
        String fpValidCode = StringUtils.getRandomNum(6);
        log.info("生成动态验证码：{}", fpValidCode);
        WebUtil.setHttpSession(Constants.USER_CHECKCODE, fpValidCode);
        if ("mobile".equals(op)) {
            if (StringUtils.isBlank(user.getPhone())) {
                return R.failed("该账号未设置手机号码！");
            }
            // return R.ok(sendSmsValidCode(fpValidCode));
            return R.ok(Boolean.TRUE);
        } else {
            if (StringUtils.isBlank(user.getEmail())) {
                return R.failed("该账号未设置邮件地址！");
            }
            Map<String, Object> data = new HashMap<String, Object>();
            data.put("username", loginname);
            data.put("checkcode", fpValidCode);
            return R.ok(mailHelper.sendMail(user.getEmail(), "邮箱验证码", data));
        }
    }

    // 注册用户
    @SysLog("注册用户")
    @ResponseBody
    @PostMapping(value = "/register")
    public R registerUser(SysUser userVo) {
        return R.ok(userService.registerUser(userVo));
    }

    // 校验用户密码正确性
    @PostMapping(value = "/checkPassword")
    @ResponseBody
    public String checkPassword(String oldPassword) {
        String result = "false";

        // 防止伪造表单传参
        if (StringUtils.isEmpty(oldPassword)) {
            return "false";
        }
        String password = AesUtil.decryptStr(oldPassword);
        SysUser user = userService.getById(WebUtil.getHttpCurrentUserId());

        if ((!StringUtils.isEmpty(password)) && ENCODER.matches(password, user.getPassword())) {
            result = "true";
        }
        return result;
    }

    // 修改密码
    @SysLog("修改密码")
    @ResponseBody
    @PostMapping(value = "/modifyPwd")
    public R modifyPassword(SysUser user) {
        if (StringUtils.isEmpty(user.getPassword())) {
            return R.failed("没有找到密码字段");
        }
        // 解密
        user.setPassword(AesUtil.decryptStr(user.getPassword()));
        if (WebUtil.getHttpCurrentUserId() != null) {
            user.setUserId(WebUtil.getHttpCurrentUserId());
        } else {
            SysUser quser = userService.getOne(new QueryWrapper<SysUser>().eq("loginname", user.getLoginname()));
            user.setUserId(quser.getUserId());
        }
        user.setPassword(ENCODER.encode(user.getPassword()));
        user.setUpdateTime(new Date());
        return R.ok(userService.updateById(user));
    }

    // 个人信息页
    @GetMapping("/goProfile")
    public String goProfile(ModelMap mmap) {
        SysUser user = userService.selectUserVoById(WebUtil.getHttpCurrentUserId());
        if (StringUtils.isNotEmpty(user.getAvatar())) {
            user.setAvatar(sysFileService.getFileUrl(user.getAvatar()));
        }
        mmap.put("user", user);
        return "home/myprofile";
    }

    /**
     * 修改头像
     */
    @GetMapping("/avatar")
    public String avatar(ModelMap mmap) {
        mmap.put("user", userService.selectUserVoById(WebUtil.getHttpCurrentUserId()));
        return "home/avatar";
    }

    /**
     * 保存头像
     */
    @SysLog("修改个人信息")
    @PostMapping("/updateAvatar")
    @ResponseBody
    public R updateAvatar(@RequestParam("avatarfile") MultipartFile file) {
        SysUser currentUser = new SysUser();
        R rlt = sysFileService.uploadFile(file);
        if (rlt.getCode() == 0) {
            Map<String, String> resultMap = (Map<String, String>)rlt.getData();
            currentUser.setAvatar(resultMap.get("fileName"));
            currentUser.setUserId(WebUtil.getHttpCurrentUserId());
            currentUser.setUpdateTime(new Date());
            return R.ok(userService.updateById(currentUser));
        }
        return rlt;
    }

    @SysLog("修改个人信息")
    @ResponseBody
    @PostMapping(value = "/saveProfile")
    public R saveProfile(SysUser user) {
    	user.setUpdateTime(new Date());
        return R.ok(userService.updateById(user));
    }

    /**
     * 删除用户信息
     *
     * @param id
     *            ID
     * @return R
     */
    @SysLog("删除用户信息")
    @ResponseBody
    @DeleteMapping("/{ids}")
    @PreAuthorize("@pms.hasPermission('sys_user_del')")
    @ApiOperation(value = "删除用户", notes = "根据ID删除用户")
    @ApiImplicitParam(name = "ids", value = "用户ID", required = true, paramType = "path")
    public R userDel(@PathVariable String ids) {
        String[] userIds = ids.split(",");
        for (String id : userIds) {
            SysUser sysUser = userService.getById(Integer.parseInt(id));
            R.ok(userService.deleteUserById(sysUser));
        }
        return R.ok(Boolean.TRUE);
    }

    /**
     * 添加用户
     *
     * @param userDto
     *            用户信息
     * @return success/false
     */
    @SysLog("添加用户")
    @ResponseBody
    @PostMapping
    @PreAuthorize("@pms.hasPermission('sys_user_add')")
    public R user(SysUser userDto) {
    	userDto.setUserId(2);
        return R.ok(userService.saveUser(userDto));
    }

    /**
     * 更新用户信息
     *
     * @param userDto
     *            用户信息
     * @return R
     */
    @SysLog("更新用户信息")
    @ResponseBody
    @PutMapping
    @PreAuthorize("@pms.hasPermission('sys_user_edit')")
    public R updateUser(SysUser userDto) {
        return R.ok(userService.updateUser(userDto));
    }

    /**
     * 导出Excel文件
     *
     */
    @GetMapping("/export")
    public void doExcel(HttpServletResponse response, SysUser sysuser) {
        Workbook workbook = DefaultExcelBuilder.of(SysUser.class)
            .build(userService.getUsersWithRole(sysuser));
        AttachmentExportUtil.export(workbook, "用户数据", response);
    }

    @ResponseBody
    @GetMapping("/importTemplate")
    @PreAuthorize("@pms.hasPermission('sys_user_add')")
    public R importTemplate() {
        return R.ok(null, "用户数据.xlsx");
    }

    @SysLog("导入用户")
    @PostMapping(value = "/importData")
    @PreAuthorize("@pms.hasPermission('sys_user_add')")
    public void importData(MultipartFile file, boolean updateSupport,boolean submitType, HttpServletRequest request,HttpServletResponse response) {

        List<SysUser> result = null;

        if(submitType) {
            response.setContentType("text/html;charset=utf-8");
        }else {
            response.setContentType("text/json;charset=utf-8");
        }

        try{
            result = SaxExcelReader.of(SysUser.class).sheet(0) // 0代表第一个，如果为0，可省略该操作，也可sheet("名称")读取，.csv文件无效
                .rowFilter(row -> row.getRowNum() > 0) // 如无需过滤，可省略该操作，0代表第一行
                .charset("GBK") // 目前仅.csv文件有效，设置当前文件的编码
                .read(file.getInputStream());
        } catch (IOException e) {
            log.error("解析文件失败");
            responsePage(response,R.failed("解析文件失败"));
        }

        try {
            result.stream().forEach(sysUser -> {
                boolean hasDept = false;
                UserInfoValidator.isLegalUser(sysUser);
                if (StringUtils.isNotEmpty(sysUser.getPassword())) {
                    sysUser.setPassword(ENCODER.encode(sysUser.getPassword()));
                } else {
                    throw new ExcelImportException("登录名:" + sysUser.getLoginname() + "校验未通过,请录入密码");
                }
                if (StringUtils.isNotEmpty(sysUser.getDeptName())) {
                    List<SysDept> deptlist = sysDeptService.list(Wrappers.<SysDept>query().lambda()
                        .eq(SysDept::getName, sysUser.getDeptName()).eq(SysDept::getDelFlag, Constants.STATUS_NORMAL));
                    if (CollUtil.isNotEmpty(deptlist)) {
                        sysUser.setDeptId(deptlist.get(0).getDeptId());
                        hasDept = true;
                    }
                }
                if (!hasDept) {
                    throw new ExcelImportException("登录名:" + sysUser.getLoginname() + "所属部门不正确,导入失败");
                }
            });
            if (!updateSupport) {
            	for (SysUser sysUser2 : result) {
            		userService.save(sysUser2);
				}
                responsePage(response,R.ok(true));
            } else {
                for (SysUser user : result) {
                    userService.saveOrUpdate(user,
                        Wrappers.<SysUser>update().lambda().eq(SysUser::getLoginname, user.getLoginname()));
                }
                responsePage(response,R.ok(Boolean.TRUE));
            }
        }catch (ExcelImportException e) {
            responsePage(response,R.failed(e.getMessage()));
        }catch (Exception e) {
            responsePage(response,R.failed("导入失败，请检查是否有重复项"));
        }
    }

    /**
     * 用户授权角色
     */
    @SysLog("分配角色")
    @ResponseBody
    @PostMapping("/insertAuthRole")
    @PreAuthorize("@pms.hasPermission('sys_user_edit')")
    public R insertAuthRole(Integer userId, Integer[] roleIds) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginname(userService.getById(userId).getLoginname());
        sysUser.setRoleIds(Arrays.asList(roleIds));
        return R.ok(userService.updateUser(sysUser));
    }

    private void responsePage(HttpServletResponse response,R r) {
        try {
            response.getOutputStream().write(JSON.toJSONBytes(r));
        }catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}
